package com.ikingtech.platform.service.application.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ikingtech.framework.sdk.application.model.ApplicationModelApiDTO;
import com.ikingtech.framework.sdk.application.model.ApplicationModelDTO;
import com.ikingtech.framework.sdk.application.model.ApplicationModelRelationDTO;
import com.ikingtech.framework.sdk.application.model.ApplicationQueryParamDTO;
import com.ikingtech.framework.sdk.base.model.PageResult;
import com.ikingtech.framework.sdk.context.security.Me;
import com.ikingtech.framework.sdk.enums.common.JavaFieldTypeEnum;
import com.ikingtech.framework.sdk.utils.Tools;
import com.ikingtech.platform.service.application.entity.ApplicationModelDO;
import com.ikingtech.platform.service.application.entity.ApplicationModelFieldDO;
import com.ikingtech.platform.service.application.entity.ApplicationModelRelationDO;
import com.ikingtech.platform.service.application.mapper.ApplicationModelMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author tie yan
 */
@Service
@RequiredArgsConstructor
public class ApplicationModelService extends ServiceImpl<ApplicationModelMapper, ApplicationModelDO> {

    private final ApplicationModelFieldService fieldService;

    private final ApplicationModelRelationService modelRelationService;

    public List<ApplicationModelDTO> modelConvert(List<ApplicationModelDO> entities) {
        return this.modelConvert(entities, false);
    }

    public List<ApplicationModelDTO> modelConvert(List<ApplicationModelDO> entities, Boolean showSlaveModelField) {
        if (Tools.Coll.isBlank(entities)) {
            return new ArrayList<>();
        }
        List<String> modelIds = Tools.Coll.convertList(entities, ApplicationModelDO::getId);
        List<ApplicationModelFieldDO> fieldEntities = this.fieldService.listByModelIds(modelIds);
        Map<String, List<ApplicationModelFieldDO>> fieldMap = Tools.Coll.convertGroup(fieldEntities, ApplicationModelFieldDO::getModelId);

        List<ApplicationModelRelationDO> modelRelationEntities = this.modelRelationService.listByMasterModelIds(modelIds);
        Map<String, List<ApplicationModelRelationDO>> modelRelationMap = Tools.Coll.convertGroup(modelRelationEntities, ApplicationModelRelationDO::getMasterModelId);
        if (Boolean.TRUE.equals(showSlaveModelField)) {
            Map<String, ApplicationModelDO> modelMap = Tools.Coll.convertMap(entities, ApplicationModelDO::getId);
            modelRelationMap.forEach((masterModelId, relationEntities) ->
                    fieldMap.get(masterModelId).addAll(Tools.Coll.convertList(relationEntities, relationEntity -> {
                        ApplicationModelFieldDO field = new ApplicationModelFieldDO();
                        field.setId(Tools.Id.uuid());
                        field.setModelId(masterModelId);
                        field.setType(JavaFieldTypeEnum.LIST.name());
                        field.setName(modelMap.get(relationEntity.getModelId()).getCode() + "List");
                        return field;
                    })));
        }

        List<ApplicationModelDO> slaveModelEntities = Tools.Coll.isBlank(modelRelationEntities) ? new ArrayList<>() : this.listByIds(Tools.Coll.convertList(modelRelationEntities, ApplicationModelRelationDO::getModelId));
        Map<String, ApplicationModelDO> slaveModelMap = Tools.Coll.convertMap(slaveModelEntities, ApplicationModelDO::getId);
        return Tools.Coll.convertList(entities, entity -> this.modelConvert(entity, fieldMap.get(entity.getId()), modelRelationMap.get(entity.getId()), slaveModelMap));
    }

    public ApplicationModelDTO modelConvert(ApplicationModelDO entity,
                                            List<ApplicationModelFieldDO> fieldEntities,
                                            List<ApplicationModelRelationDO> modelRelationEntities,
                                            Map<String, ApplicationModelDO> slaveModelMap) {
        ApplicationModelDTO model = Tools.Bean.copy(entity, ApplicationModelDTO.class);
        if (null != model.getStatus()) {
            model.setStatusName(model.getStatus().description);
        }
        model.setFields(this.fieldService.modelConvert(fieldEntities));
        model.setApis(Tools.Coll.newList(
                () -> {
                    ApplicationModelApiDTO api = new ApplicationModelApiDTO();
                    api.setUri("/" + entity.getCode() + "/add");
                    api.setName("新增");
                    return api;
                },
                () -> {
                    ApplicationModelApiDTO api = new ApplicationModelApiDTO();
                    api.setUri("/" + entity.getCode() + "/delete");
                    api.setName("删除");
                    return api;
                },
                () -> {
                    ApplicationModelApiDTO api = new ApplicationModelApiDTO();
                    api.setUri("/" + entity.getCode() + "/update");
                    api.setName("更新");
                    return api;
                },
                () -> {
                    ApplicationModelApiDTO api = new ApplicationModelApiDTO();
                    api.setUri("/" + entity.getCode() + "/list/page");
                    api.setName("分页查询");
                    return api;
                },
                () -> {
                    ApplicationModelApiDTO api = new ApplicationModelApiDTO();
                    api.setUri("/" + entity.getCode() + "/list/all");
                    api.setName("全量查询");
                    return api;
                }
        ));
        model.setSlaveModels(Tools.Coll.convertList(modelRelationEntities, modelRelationEntity -> {
            ApplicationModelRelationDTO modelRelation = Tools.Bean.copy(modelRelationEntity, ApplicationModelRelationDTO.class);
            modelRelation.setModelName(slaveModelMap.get(modelRelation.getModelId()).getName());
            return modelRelation;
        }));
        return model;
    }

    public PageResult<ApplicationModelDO> listPage(ApplicationQueryParamDTO queryParam) {
        return PageResult.build(this.page(new Page<>(queryParam.getPage(), queryParam.getRows()), Wrappers.<ApplicationModelDO>lambdaQuery()
                .like(Tools.Str.isNotBlank(queryParam.getName()), ApplicationModelDO::getName, queryParam.getName())
                .eq(Tools.Str.isNotBlank(queryParam.getStatus()), ApplicationModelDO::getStatus, queryParam.getStatus())
                .eq(Tools.Str.isNotBlank(Me.appCode()), ApplicationModelDO::getAppCode, Me.appCode())
                .orderByDesc(ApplicationModelDO::getCreateTime)));
    }

    public boolean exist(String id) {
        return this.baseMapper.exists(Wrappers.<ApplicationModelDO>lambdaQuery().eq(ApplicationModelDO::getId, id));
    }
}
